/*-------------------------------------------------------------------------
 *
 * params.h
 *	  支持查找与参数节点相关联的值。
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/nodes/params.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef PARAMS_H
#define PARAMS_H

/* 前置声明，以避免包含其他头文件 */
struct Bitmapset;
struct ExprState;
struct Param;
struct ParseState;


/*
 *	  ParamListInfo
 *
 *	  ParamListInfo 结构用于将参数传递给执行器
 *	  以用于参数化计划。我们支持两种基本方法来提供
 *	  参数值，"静态" 方式和 "动态" 方式。
 *
 *	  在静态方法中，每个参数的数据存储在
 *	  附加到 ParamListInfo 结构的 ParamExternData 结构数组中。
 *	  数组中的每个条目定义了要替代的值
 *	  对于 PARAM_EXTERN 参数。PARAM_EXTERN 参数的 "paramid"
 *	  可以范围从 1 到 numParams。
 *
 *	  虽然参数编号通常是连续的，但我们允许
 *	  ptype == InvalidOid 来标志一个未使用的数组条目。
 *
 *	  pflags 是一个标志字段。目前唯一使用的位是：
 *	  PARAM_FLAG_CONST 表示计划者可以将此参数
 *	  视为常量（即，生成的计划仅适用于此值
 *	  的参数）。
 *
 *	  在动态方法中，所有参数值的访问都是通过
 *	  位于 ParamListInfo 结构中的钩子函数完成的。在这种情况下，
 *	  ParamExternData 数组通常未使用且未分配；
 *	  但 paramid 的合法范围仍然是 1 到 numParams。
 *
 *	  虽然数据结构实际上是一个数组，而不是一个列表，但我们保留
 *	  旧的 typedef 名称以避免不必要的代码更改。
 *
 *	  可以与 ParamListInfo 结构关联的 3 个钩子函数：
 *
 *	  如果 paramFetch 不为 null，则调用它以获取特定参数 ID 的 ParamExternData，
 *	  而不是访问 ParamExternData 数组的相关元素。这支持数组根本不存在的情况，
 *	  以及数组中数据可能陈旧或延迟评估的情况。paramFetch 必须返回描述指定 param ID 的
 *	  ParamExternData 结构的地址；上述关于 ptype == InvalidOid 标志着无效
 *	  param ID 的约定仍然适用。返回的结构可以放置在
 *	  调用者提供的 "工作区" 中，或者如果更方便，可以在由 paramFetch 钩子控制的存储中。
 *	  （在任何一种情况下，该结构都不应被期望长时间存在。）
 *	  如果 "speculative" 为真，则 paramFetch 钩子不应冒险出现错误
 *	  来获取参数值，而应报告无效参数。
 *
 *	  如果 paramCompile 不为 null，则控制 execExpr.c 为 PARAM_EXTERN Param 节点编译的内容 ---
 *	  通常，这个钩子将发出 EEOP_PARAM_CALLBACK 步骤。这允许在编译表达式中优化掉不必要的工作。
 *
 *	  如果 parserSetup 不为 null，则在查询需要重新解析/规划时调用它以重新实例化
 *	  原始解析钩子。如果参数类型可能会不时变化，这尤其有用，
 *	  因为它可以替代向解析器提供一组固定的参数类型的需要。
 *
 *	  请注意，paramFetch 和 paramCompile 钩子实际上是传递了 ParamListInfo 结构的地址；
 *	  因此它们可以访问所有三个 "arg" 字段，并且 paramFetchArg 和 paramCompileArg 之间的区别相当任意。
 */

#define PARAM_FLAG_CONST	0x0001	/* 参数是常量 */

typedef struct ParamExternData
{
	Datum		value;			/* 参数值 */
	bool		isnull;			/* 它是 NULL 吗？ */
	uint16		pflags;			/* 标志位，见上文 */
	Oid			ptype;			/* 参数的数据类型，或 0 */
} ParamExternData;

typedef struct ParamListInfoData *ParamListInfo;

typedef ParamExternData *(*ParamFetchHook) (ParamListInfo params,
											int paramid, bool speculative,
											ParamExternData *workspace);

typedef void (*ParamCompileHook) (ParamListInfo params, struct Param *param,
								  struct ExprState *state,
								  Datum *resv, bool *resnull);

typedef void (*ParserSetupHook) (struct ParseState *pstate, void *arg);

typedef struct ParamListInfoData
{
	ParamFetchHook paramFetch;	/* 参数获取钩子 */
	void	   *paramFetchArg;
	ParamCompileHook paramCompile;	/* 参数编译钩子 */
	void	   *paramCompileArg;
	ParserSetupHook parserSetup;	/* 解析器设置钩子 */
	void	   *parserSetupArg;
	char	   *paramValuesStr; 
	int			numParams;		/* nominal/maximum # of Params represented */

	/*
	 * params[] 在提供 paramFetch 的情况下可以长度为零；否则它
	 * 必须长度为 numParams。
	 */
	ParamExternData params[FLEXIBLE_ARRAY_MEMBER];
}			ParamListInfoData;


/* ----------------
 *	  ParamExecData
 *
 *	  ParamExecData 条目用于执行器内部参数
 *	  （即，传入或传出子查询的值）。PARAM_EXEC Param 的 paramid 是一个
 *	  （以零为基数）索引，指向 ParamExecData 记录的数组，通过
 *	  es_param_exec_vals 或 ecxt_param_exec_vals 进行引用。
 *
 *	  如果 execPlan 不是 NULL，它指向一个需要
 *	  执行以生成值的 SubPlanState 节点。 这
 *	  是为了我们可以进行 InitPlans 的惰性求值：它们在
 *	  需要结果值时不执行/不执行。否则当需要时，假设值是有效的。
 * ----------------
 */

typedef struct ParamExecData
{
	void	   *execPlan;		/* 应为 "SubPlanState *" */
	Datum		value;
	bool		isnull;
} ParamExecData;

/* ParamsErrorCallback 的参数类型 */
typedef struct ParamsErrorCbData
{
	const char *portalName;
	ParamListInfo params;
} ParamsErrorCbData;

/* 在 src/backend/nodes/params.c 中找到的函数 */
extern ParamListInfo makeParamList(int numParams);
extern ParamListInfo copyParamList(ParamListInfo from);
extern Size EstimateParamListSpace(ParamListInfo paramLI);
extern void SerializeParamList(ParamListInfo paramLI, char **start_address);
extern ParamListInfo RestoreParamList(char **start_address);
extern char *BuildParamLogString(ParamListInfo params, char **paramTextValues,
								 int valueLen);
extern void ParamsErrorCallback(void *arg);

#endif							/* PARAMS_H */
